feat(aparavi): AQL node, multi-tab chat app, auth page removal, reconnect fix#1150
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis pull request introduces an Aparavi AQL node for LLM-driven SQL query generation with safety validation, along with a full-screen Aparavi chat UI app. Supporting infrastructure updates enable app-switching to manage connection monitors and display names. The shared-UI connection details view is refactored from an inline panel to a modal dialog. ChangesAparavi AQL Node Implementation
Aparavi UI App and Supporting Infrastructure
Sequence Diagram(s)sequenceDiagram
participant User
participant ChatView as Chat UI
participant AparaviApp
participant Pipeline as Aparavi Pipeline
participant Agent as Aparavi Agent
participant AQLTool as AQL Tool
participant LLM
participant AqlClient
User->>ChatView: sends question
ChatView->>AparaviApp: handleSend(text)
AparaviApp->>Pipeline: sendMessage(client, pipelineToken, text)
Pipeline->>Agent: invoke with question
Agent->>AQLTool: get_data(question)
AQLTool->>LLM: invoke _generate_aql(Question)
LLM-->>AQLTool: raw AQL string
AQLTool->>AQLTool: _aql_safe(aql)
AQLTool->>AqlClient: execute(aql)
AqlClient-->>AQLTool: {rows, count, aql}
AQLTool-->>Agent: {rows, aql, count}
Agent-->>Pipeline: response
Pipeline-->>ChatView: assistant message
ChatView-->>User: displays results
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🤖 Internal: Discord sync markerAuto-managed by the Discord notification workflow. Stores the linked Discord message ID. Do not edit or delete. |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@nodes/src/nodes/aparavi_aql/aql_client.py`:
- Around line 80-95: The code assumes envelope = resp.json() is a dict and calls
envelope.get(...), which raises AttributeError for non-object JSON; update the
response handling in the method that assigns envelope (envelope = resp.json())
to first validate that envelope is an instance of dict (e.g.,
isinstance(envelope, dict)) and if not raise a RuntimeError with a clear message
(e.g., "Aparavi API returned non-object JSON response"), so subsequent accesses
(envelope.get, data = envelope.get('data'), etc.) are safe; adjust any type
hints/comments around envelope/rows/columns accordingly.
In `@nodes/src/nodes/aparavi_aql/aql_schema.py`:
- Around line 223-226: get_schema_dict currently returns the global COLUMNS by
reference, allowing callers to mutate shared state; change get_schema_dict (the
function) so it returns a defensive copy of COLUMNS (e.g., shallow copy via
list(COLUMNS) or a deepcopy if COLUMNS contains nested mutables) in the returned
dict so callers cannot modify the module-level COLUMNS.
In `@nodes/src/nodes/aparavi_aql/IInstance.py`:
- Around line 146-159: The retry loop currently only catches RuntimeError from
client.execute, so failures thrown by _generate_aql (or the LLM it calls) escape
the retry/error path; modify the loop around _generate_aql and subsequent safety
check so generation is inside the try/except (or add a specific try around
_generate_aql) and catch generation/LLM errors, set last_error and previous_aql
appropriately, and continue retries instead of re-raising; ensure the error
response returned after exhausting retries includes the last_error and the last
attempted aql, and apply the same change to the similar block referenced by
_generate_aql at the other location (the block around lines with previous_aql
handling at 324-327).
- Around line 50-63: Replace the unsafe-word blacklist with a strict SELECT-only
allowlist: remove or stop using _UNSAFE_PATTERN and change _aql_safe to validate
the entire AQL string against a single-statement SELECT regex (e.g., ensure it
starts with SELECT, contains no additional statements, and optionally ends with
a single semicolon) using re.IGNORECASE; update any other checks that used
_UNSAFE_PATTERN (including the usage around the other AQL validation at lines
noted in the review) to call the new _aql_safe so only single SELECT statements
are permitted for execution.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 24294e0d-b797-4ba5-a3de-712fc77ccf08
📒 Files selected for processing (7)
nodes/src/nodes/aparavi_aql/IGlobal.pynodes/src/nodes/aparavi_aql/IInstance.pynodes/src/nodes/aparavi_aql/__init__.pynodes/src/nodes/aparavi_aql/aql_client.pynodes/src/nodes/aparavi_aql/aql_schema.pynodes/src/nodes/aparavi_aql/requirements.txtnodes/src/nodes/aparavi_aql/services.json
723a44f to
eae5b66
Compare
- aql_client: guard envelope type before accessing dict fields — non-dict JSON responses (list, string) now raise a clear RuntimeError - aql_schema: return defensive copy of COLUMNS from get_schema_dict() so downstream mutation can't alter global state - IInstance: replace mutation blacklist with SELECT-only allowlist gate — query must start with SELECT and contain no unsafe keywords - IInstance: wrap _generate_aql in try/except inside retry loop so LLM generation failures also retry instead of raising immediately Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
♻️ Duplicate comments (4)
nodes/src/nodes/aparavi_aql/aql_schema.py (1)
223-225:⚠️ Potential issue | 🟠 Major | ⚡ Quick winReturn a defensive copy of
COLUMNSfromget_schema_dict().Line 225 exposes mutable global state by reference, so downstream mutation can corrupt schema output for later calls.
Suggested fix
def get_schema_dict() -> Dict[str, Any]: """Return the structured schema dict for the get_schema tool response.""" - return {'store': 'STORE', 'columns': COLUMNS} + return {'store': 'STORE', 'columns': [col.copy() for col in COLUMNS]}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@nodes/src/nodes/aparavi_aql/aql_schema.py` around lines 223 - 225, get_schema_dict currently returns the global COLUMNS by reference which allows downstream callers to mutate shared state; update get_schema_dict to return a defensive copy of COLUMNS (e.g., use copy.deepcopy(COLUMNS) or construct new dict/list copies) so the returned value cannot modify the module-level COLUMNS; keep the return shape {'store': 'STORE', 'columns': <copied columns>} and import/use the copy module if using deepcopy.nodes/src/nodes/aparavi_aql/aql_client.py (1)
80-93:⚠️ Potential issue | 🟠 Major | ⚡ Quick winGuard JSON envelope type before dictionary access.
At Line 80,
resp.json()can return a non-object JSON value; Line 88 then calls.get(...)and crashes withAttributeError, bypassing yourRuntimeErrorwrapping path.Suggested fix
resp.raise_for_status() envelope = resp.json() + if not isinstance(envelope, dict): + raise RuntimeError('Aparavi API returned non-object JSON envelope') @@ - data = envelope.get('data') or {} + data = envelope.get('data') or {} + if not isinstance(data, dict): + raise RuntimeError('Aparavi API returned invalid "data" payload')🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@nodes/src/nodes/aparavi_aql/aql_client.py` around lines 80 - 93, The code assumes envelope (from resp.json()) is a dict but resp.json() can return non-dict values; update the handling in the response parsing (around envelope = resp.json() and subsequent checks) to validate the type before using dict methods: after envelope = resp.json(), check isinstance(envelope, dict) and if not raise a RuntimeError (e.g., "Aparavi API returned non-object JSON envelope") so the existing envelope.get('status'), envelope.get('message'), envelope.get('data') and data.get('objects') calls are safe; ensure this validation sits before the if envelope.get('status') != 'OK' block and before data = envelope.get('data') or {}.nodes/src/nodes/aparavi_aql/IInstance.py (2)
146-159:⚠️ Potential issue | 🟠 Major | ⚡ Quick winInclude AQL generation failures in the retry path.
At Line 147,
_generate_aql(...)runs outside thetry, so LLM/generation exceptions bypass retries and return-shape handling.Suggested fix
for _ in range(_MAX_AQL_RETRIES): - aql = self._generate_aql(question_text, previous_aql=previous_aql, error=last_error) - - # Safety check — block mutation queries - if not _aql_safe(aql): - return {'error': 'Generated AQL contains unsafe operations', 'aql': aql, 'rows': []} - try: + aql = self._generate_aql(question_text, previous_aql=previous_aql, error=last_error) + + # Safety check — block mutation queries + if not _aql_safe(aql): + return {'error': 'Generated AQL contains unsafe operations', 'aql': aql, 'rows': []} + result = client.execute(aql) return {'rows': result['rows'], 'aql': aql, 'count': result['count']} - except RuntimeError as exc: + except Exception as exc: last_error = str(exc) - previous_aql = aql + previous_aql = locals().get('aql', previous_aql)Also applies to: 324-327
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@nodes/src/nodes/aparavi_aql/IInstance.py` around lines 146 - 159, The AQL generation call _generate_aql is currently outside the try so LLM/generation exceptions escape the retry loop; wrap the call to _generate_aql inside the same try/except that handles client.execute so generation errors set last_error (e.g., str(exc)) and previous_aql as appropriate and allow the loop to continue for up to _MAX_AQL_RETRIES, then after retries return the consistent error shape {'error': ..., 'aql': aql_or_none, 'rows': []}; apply the same change to the other occurrence around lines 324-327 (same function/method where _generate_aql and _aql_safe are used) so both generation and execution exceptions are retried and produce the same return structure.
50-63:⚠️ Potential issue | 🟠 Major | ⚡ Quick winEnforce a strict single-statement
SELECTallowlist, not only a mutation blacklist.At Line 60, non-
SELECT/multi-statement queries can still pass if they avoid listed keywords. The gate should require oneSELECTstatement (optional trailing semicolon) and reject additional statements.Suggested fix
_UNSAFE_PATTERN = re.compile( r'\b(INSERT|UPDATE|DELETE|DROP|TRUNCATE|ALTER|CREATE|EXEC|EXECUTE)\b', re.IGNORECASE, ) +_SELECT_START = re.compile(r'^\s*SELECT\b', re.IGNORECASE) @@ def _aql_safe(aql: str) -> bool: - """Return True if the AQL contains no unsafe mutation keywords.""" - return not _UNSAFE_PATTERN.search(aql) + """Allow only a single SELECT statement with no unsafe tokens.""" + text = aql.strip() + if text.endswith(';'): + text = text[:-1].rstrip() + if ';' in text: + return False + if not _SELECT_START.match(text): + return False + return not _UNSAFE_PATTERN.search(text)Also applies to: 149-151
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@nodes/src/nodes/aparavi_aql/IInstance.py` around lines 50 - 63, The current _aql_safe function uses _UNSAFE_PATTERN to blacklist mutation keywords but must instead enforce a strict single-statement SELECT allowlist: update _aql_safe to validate that the input AQL matches exactly one SELECT statement (optionally with a single trailing semicolon and whitespace) and rejects anything else (multiple statements, non-SELECT verbs, or embedded semicolons). Locate the _aql_safe function and replace the blacklist logic with a regex or parser that enforces: start-of-string, optional whitespace, the word SELECT, any characters, optional whitespace, optional single semicolon, optional whitespace, end-of-string; also update any other usage of _aql_safe (e.g., the other occurrence referencing the same check) so they use the new strict validation and not the _UNSAFE_PATTERN blacklist.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@nodes/src/nodes/aparavi_aql/aql_client.py`:
- Around line 80-93: The code assumes envelope (from resp.json()) is a dict but
resp.json() can return non-dict values; update the handling in the response
parsing (around envelope = resp.json() and subsequent checks) to validate the
type before using dict methods: after envelope = resp.json(), check
isinstance(envelope, dict) and if not raise a RuntimeError (e.g., "Aparavi API
returned non-object JSON envelope") so the existing envelope.get('status'),
envelope.get('message'), envelope.get('data') and data.get('objects') calls are
safe; ensure this validation sits before the if envelope.get('status') != 'OK'
block and before data = envelope.get('data') or {}.
In `@nodes/src/nodes/aparavi_aql/aql_schema.py`:
- Around line 223-225: get_schema_dict currently returns the global COLUMNS by
reference which allows downstream callers to mutate shared state; update
get_schema_dict to return a defensive copy of COLUMNS (e.g., use
copy.deepcopy(COLUMNS) or construct new dict/list copies) so the returned value
cannot modify the module-level COLUMNS; keep the return shape {'store': 'STORE',
'columns': <copied columns>} and import/use the copy module if using deepcopy.
In `@nodes/src/nodes/aparavi_aql/IInstance.py`:
- Around line 146-159: The AQL generation call _generate_aql is currently
outside the try so LLM/generation exceptions escape the retry loop; wrap the
call to _generate_aql inside the same try/except that handles client.execute so
generation errors set last_error (e.g., str(exc)) and previous_aql as
appropriate and allow the loop to continue for up to _MAX_AQL_RETRIES, then
after retries return the consistent error shape {'error': ..., 'aql':
aql_or_none, 'rows': []}; apply the same change to the other occurrence around
lines 324-327 (same function/method where _generate_aql and _aql_safe are used)
so both generation and execution exceptions are retried and produce the same
return structure.
- Around line 50-63: The current _aql_safe function uses _UNSAFE_PATTERN to
blacklist mutation keywords but must instead enforce a strict single-statement
SELECT allowlist: update _aql_safe to validate that the input AQL matches
exactly one SELECT statement (optionally with a single trailing semicolon and
whitespace) and rejects anything else (multiple statements, non-SELECT verbs, or
embedded semicolons). Locate the _aql_safe function and replace the blacklist
logic with a regex or parser that enforces: start-of-string, optional
whitespace, the word SELECT, any characters, optional whitespace, optional
single semicolon, optional whitespace, end-of-string; also update any other
usage of _aql_safe (e.g., the other occurrence referencing the same check) so
they use the new strict validation and not the _UNSAFE_PATTERN blacklist.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 1bf6829e-8764-44aa-8640-03fb691e8cbd
📒 Files selected for processing (7)
nodes/src/nodes/aparavi_aql/IGlobal.pynodes/src/nodes/aparavi_aql/IInstance.pynodes/src/nodes/aparavi_aql/__init__.pynodes/src/nodes/aparavi_aql/aql_client.pynodes/src/nodes/aparavi_aql/aql_schema.pynodes/src/nodes/aparavi_aql/requirements.txtnodes/src/nodes/aparavi_aql/services.json
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
nodes/src/nodes/aparavi_aql/aql_schema.py (1)
223-225:⚠️ Potential issue | 🟡 Minor | 💤 Low valueShallow copy doesn't protect nested dict mutation.
list(COLUMNS)creates a new list but the dict elements are still shared references. A caller mutatingcolumns[0]['name']would corrupt global state. Per the previous review suggestion, use a shallow copy of each dict.Suggested fix
def get_schema_dict() -> Dict[str, Any]: """Return the structured schema dict for the get_schema tool response.""" - return {'store': 'STORE', 'columns': list(COLUMNS)} + return {'store': 'STORE', 'columns': [col.copy() for col in COLUMNS]}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@nodes/src/nodes/aparavi_aql/aql_schema.py` around lines 223 - 225, get_schema_dict currently returns {'store': 'STORE', 'columns': list(COLUMNS)} which leaves the dict elements in COLUMNS shared; change it to return a new list of shallow-copied column dicts so callers can't mutate global state (e.g., build columns as [col.copy() for col in COLUMNS] and return {'store': 'STORE', 'columns': that_list}); update the get_schema_dict function to use this shallow-copy approach referencing COLUMNS.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/aparavi-ui/tsconfig.json`:
- Around line 3-4: Update the TypeScript target in apps/aparavi-ui/tsconfig.json
from "ES2020" to "ES2022" so it matches the repo's Coderabbit config; locate the
"target" property in that file (alongside the existing "module": "ESNext") and
set its value to "ES2022" (no other changes required).
In `@packages/shared-ui/src/modules/server/components/ConnectionsTab.tsx`:
- Around line 122-130: The modal markup in ConnectionsTab (the div using
commonStyles.modalOverlay and the inner div using styles.modalDialog) lacks
dialog semantics; update the inner modal container to include role="dialog" and
aria-modal="true" and provide an accessible name via aria-labelledby (pointing
to the header span) or aria-label so screen readers announce the dialog; ensure
the close button (onClick={onClose}) remains keyboard-accessible and that the
outer overlay still handles onClick={onClose} while the inner div preserves
e.stopPropagation().
In `@packages/shared-ui/src/modules/server/components/OverviewTab.tsx`:
- Line 451: The table row in OverviewTab.tsx is only clickable via mouse (the
<tr ... onClick={() => setSelectedConnId(conn.id)}> using S.clickableRow), so
make it keyboard-accessible by adding tabIndex={0} and role="button" to the <tr>
and implementing an onKeyDown handler that calls setSelectedConnId(conn.id) when
Enter or Space is pressed (and preventDefault for Space to avoid page scroll),
keeping the existing onClick behavior; this preserves mouse behavior and enables
keyboard users to open the detail modal.
---
Duplicate comments:
In `@nodes/src/nodes/aparavi_aql/aql_schema.py`:
- Around line 223-225: get_schema_dict currently returns {'store': 'STORE',
'columns': list(COLUMNS)} which leaves the dict elements in COLUMNS shared;
change it to return a new list of shallow-copied column dicts so callers can't
mutate global state (e.g., build columns as [col.copy() for col in COLUMNS] and
return {'store': 'STORE', 'columns': that_list}); update the get_schema_dict
function to use this shallow-copy approach referencing COLUMNS.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: ddcd4b80-ae40-4cc7-b0fa-d2a2db0f4642
⛔ Files ignored due to path filters (2)
apps/aparavi-ui/src/icon.svgis excluded by!**/*.svgpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml,!pnpm-lock.yaml
📒 Files selected for processing (16)
apps/aparavi-ui/package.jsonapps/aparavi-ui/rsbuild.config.mtsapps/aparavi-ui/scripts/tasks.jsapps/aparavi-ui/src/AparaviApp.tsxapps/aparavi-ui/src/AppDescriptor.tsapps/aparavi-ui/src/aparavi.pipeapps/aparavi-ui/src/index.tsapps/aparavi-ui/src/pipe.d.tsapps/aparavi-ui/tsconfig.jsonapps/shell-ui/src/components/layout/Shell.tsxnodes/src/nodes/aparavi_aql/IInstance.pynodes/src/nodes/aparavi_aql/aql_client.pynodes/src/nodes/aparavi_aql/aql_schema.pypackages/shared-ui/src/modules/server/components/ConnectionsTab.tsxpackages/shared-ui/src/modules/server/components/OverviewTab.tsxpnpm-workspace.yaml
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/shared-ui/package.json (1)
8-62:⚠️ Potential issue | 🟠 Major | ⚡ Quick winRestore
rocketrideas a peer dependency to preserve consumer contract.
shared-uistill imports (and in some places re-exports) symbols fromrocketride(useChatMessages.ts,types/project.ts,types/shell.ts). RemovingrocketridefrompeerDependenciescan break consumers that installsharedwithout explicitly addingrocketride(module/type resolution failures at build/runtime).Suggested manifest fix
"peerDependencies": { + "rocketride": "workspace:*", "remark-gfm": "^4.0.1" }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/shared-ui/package.json` around lines 8 - 62, The package removed rocketride from peerDependencies but shared-ui still imports/re-exports types and hooks from rocketride (see useChatMessages.ts, types/project.ts, types/shell.ts), which can break downstream consumers; restore rocketride to the peerDependencies in package.json with the appropriate semver range used by the monorepo (e.g., match the workspace version or a compatible ^/~ range) so consumers must provide that package, and update the package.json "peerDependencies" block to include "rocketride": "<appropriate-version-range>" to preserve the public contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@packages/shared-ui/package.json`:
- Around line 8-62: The package removed rocketride from peerDependencies but
shared-ui still imports/re-exports types and hooks from rocketride (see
useChatMessages.ts, types/project.ts, types/shell.ts), which can break
downstream consumers; restore rocketride to the peerDependencies in package.json
with the appropriate semver range used by the monorepo (e.g., match the
workspace version or a compatible ^/~ range) so consumers must provide that
package, and update the package.json "peerDependencies" block to include
"rocketride": "<appropriate-version-range>" to preserve the public contract.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 22ea14b1-e454-47db-8c2d-86ce6163729a
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml,!pnpm-lock.yaml
📒 Files selected for processing (1)
packages/shared-ui/package.json
The aparavi_aql node was written ~6 months ago against APIs that have since been replaced. This commit brings it up to date with the current rocketlib framework: 1. Tool declaration: Replaced the obsolete ToolsBase abstract class (manual _tool_query/_tool_invoke dispatch) with @tool_function decorators on IInstance. The framework now auto-discovers tools, builds descriptors, and routes invocations — no manual dispatch needed. 2. LLM invocation: Replaced the closure-based pattern (getControllerNodeIds + IInvokeLLM(op='ask', ...)) with the current self.instance.invoke(IInvokeLLM.Ask(question=q)) API. The framework handles routing to the connected LLM node automatically. 3. Deleted aql_driver.py entirely — all business logic (AQL generation, retry loop, safety regex) now lives directly on IInstance methods. 4. Simplified IGlobal.py — removed AqlDriver instantiation, kept only the AqlClient HTTP client setup which is framework-agnostic. 5. Added docstrings to reach CI coverage threshold. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- aql_client: guard envelope type before accessing dict fields — non-dict JSON responses (list, string) now raise a clear RuntimeError - aql_schema: return defensive copy of COLUMNS from get_schema_dict() so downstream mutation can't alter global state - IInstance: replace mutation blacklist with SELECT-only allowlist gate — query must start with SELECT and contain no unsafe keywords - IInstance: wrap _generate_aql in try/except inside retry loop so LLM generation failures also retry instead of raising immediately Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…efactor - Add aparavi-ui MF remote app: AparaviApp component with embedded pipeline, AppDescriptor, rsbuild config, workspace registration - Shell: set clientName to 'Cloud Shell-UI' instead of first app ID - ConnectionsTab: refactor layout and connection display - OverviewTab: minor adjustments Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
shared-ui listed the vscode extension as a peerDependency, creating a circular dependency cycle (vscode → shared-ui → vscode) that pnpm warned about on every install. peerDeps are provided by consumers, so shared-ui should not reference a consuming app. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…Documents.subscribe == Problem == Cloud Shell-UI connections registered zero server-side monitors, so the browser-based rocket-ui had no visibility into running tasks. The "Other" section never appeared, clicking unknown tasks crashed, and switching apps left orphaned monitor subscriptions on the shared WebSocket connection. Meanwhile, all Cloud Shell-UI connections showed the same generic name in the server monitor, making it impossible to tell which app was active. == Root cause == When RocketSidebar replaced the old SidebarPage, the client.addMonitor() call was dropped. The new component only set up a client-side event listener without telling the server to route events to this connection. Additionally, the shell-ui had no mechanism to clean up monitors on app switch, no way to update the connection display name at runtime, and the Documents class had no public subscribe API for external listeners. == Changes == Server (task_conn.py): - Add on_rrext_identify command handler that updates _client_info['name'] at runtime and broadcasts connection_updated to dashboard subscribers so the monitor UI refreshes without polling. TypeScript SDK (client.ts): - Add clearAllMonitors(): unsubscribes all tracked monitor keys from the server then clears the local ref-count map. Used by shell-ui on app switch so the outgoing app's monitors don't leak. - Add identify(clientName): sends rrext_identify to update this connection's display name on the server. Python SDK (events.py): - Add clear_all_monitors(): mirror of the TS method. - Add identify(client_name): mirror of the TS method. Shell-UI (useWorkspaceState.ts): - On switchApp, call client.clearAllMonitors() before the new app mounts so each app starts with a clean monitor slate. - On switchApp, call client.identify() with the new app ID so the server monitor shows "Cloud Shell-UI — rocketride.pipeBuilder" etc. Shell-UI (Documents.tsx): - Add public subscribe(listener) method that returns an unsubscribe function. Wraps the private _listeners set so external code (like RocketSidebar) can react to document state changes without reaching into private internals or misusing the useStore() hook conditionally. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
b822d28 to
e3558c5
Compare
… with persistence Auth page removal & reconnect fix: - Remove standalone AuthProvider, AuthWebview, and Auth/index.tsx — the separate sign-in page was a dead end: after saving new credentials it called reconcile() but never actually reconnected, requiring a VSCode restart. Instead, auth failures now open the Settings page focused on the failing group (development/deployment), which already has test connection, full provider selection, and a working save+reconcile flow. - Add auth error banner to SettingsWebview (red bar at top with the failure message, e.g. "Invalid or revoked API key"). The banner clears on successful test connection or manual dismiss. - Fix the root reconnect bug: on AuthenticationException, call client.disconnect() to stop the persist:true client's auto-reconnect loop. Without this, the SDK client keeps retrying with stale credentials in the background, and subsequent connectToEngine() calls with fresh credentials fail silently. - Remove the "API Key cleared successfully" toast — it added noise on every auth-failure flow and wasn't useful feedback. - Update BarStatusProvider AUTH_FAILED click target from auth page to settings page. Aparavi multi-tab chat: - Rewrite AparaviApp to use Documents library for multi-tab persistent chat sessions. Each tab is an independent chat backed by a .chat JSON file via the workspace VFS. - Add AparaviSidebar with "New Chat" button and chat list. - Add chatStore (VFS read/write/rename/delete helpers) and docs (Documents singleton lifecycle). - Add Documents.discardDocument() for force-removing documents when the backing file is deleted from disk. - Add initialMessages option to useChatMessages hook so restored chats can seed the message list from persisted content. - Add chart_js tool to the Aparavi pipeline and strengthen the tool description so the agent always calls it instead of generating configs manually. - Enable status bar in aparavi-ui manifest and add app settings for Aparavi server URL, user ID, and password. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- _aql_safe: reject multi-statement queries by checking for embedded
semicolons after stripping the trailing one. The SELECT-start and
mutation-keyword checks were already in place but didn't catch
"SELECT ...; DROP ..." style injection.
- aparavi-ui tsconfig: bump target from ES2020 to ES2022 to match the
repo's .coderabbit.yaml coding guideline (strict + ES2022 + ESNext).
- ConnectionsTab modal: add role="dialog", aria-modal="true", and
aria-labelledby so screen readers announce the connection detail
overlay correctly. Add type="button" on the close button.
- OverviewTab connection rows: add tabIndex={0} and onKeyDown handler
for Enter/Space so keyboard users can open the connection detail
modal, not just mouse users.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds an end-to-end Aparavi AQL integration (node + chat UI app) and simplifies the VSCode auth recovery flow by routing auth failures to Settings, while also improving shell/server monitoring behavior and a few UI accessibility details.
Changes:
- Introduces a new
aparavi_aqltool node (AQL generation + execution + schema context + safety checks) and wires it into anaparavi-uimulti-tab persistent chat app/pipeline. - Removes the standalone VSCode auth page/provider; auth failures now open Settings (focused section + banner), and reconnect behavior is corrected by disconnecting on auth errors.
- Adds monitor-management/identify APIs across clients and server, plus UI tweaks (connection detail modal + keyboard-accessible rows) and Documents utilities.
Reviewed changes
Copilot reviewed 39 out of 42 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-workspace.yaml | Adds apps/aparavi-ui to the workspace. |
| pnpm-lock.yaml | Adds dependency entries for apps/aparavi-ui. |
| packages/shared-ui/src/modules/server/components/OverviewTab.tsx | Makes connection rows keyboard-activatable and opens a connection detail modal. |
| packages/shared-ui/src/modules/server/components/ConnectionsTab.tsx | Refactors connection details into a reusable modal with dialog ARIA attributes. |
| packages/shared-ui/src/modules/chat/types.ts | Adds initialMessages option for restoring chat history. |
| packages/shared-ui/src/modules/chat/hooks/useChatMessages.ts | Seeds chat state from initialMessages. |
| packages/client-typescript/src/client/client.ts | Adds clearAllMonitors() and identify() APIs to the TS client. |
| packages/client-python/src/rocketride/mixins/events.py | Adds clear_all_monitors() and identify() APIs to the Python client. |
| packages/ai/src/ai/modules/task/task_conn.py | Implements rrext_identify server handler and broadcasts dashboard update events. |
| nodes/src/nodes/tool_chartjs/IInstance.py | Strengthens the Chart.js tool description to encourage tool usage. |
| nodes/src/nodes/aparavi_aql/services.json | Declares the new Aparavi AQL node service + config fields. |
| nodes/src/nodes/aparavi_aql/requirements.txt | Declares no extra Python deps for the node. |
| nodes/src/nodes/aparavi_aql/IInstance.py | Implements AQL generation/execution tools with safety checks and retries. |
| nodes/src/nodes/aparavi_aql/IGlobal.py | Initializes the Aparavi AQL HTTP client from node config. |
| nodes/src/nodes/aparavi_aql/aql_schema.py | Adds fixed STORE schema and prompt text for LLM context. |
| nodes/src/nodes/aparavi_aql/aql_client.py | Implements REST client for executing/validating AQL queries. |
| nodes/src/nodes/aparavi_aql/init.py | Node module bootstrap + dependency loading. |
| apps/vscode/src/providers/views/Settings/SettingsWebview.tsx | Adds an auth-failure banner and clears it on successful connection test. |
| apps/vscode/src/providers/views/Auth/AuthWebview.tsx | Removes the standalone auth recovery webview. |
| apps/vscode/src/providers/shared/connection-message-handler.ts | Updates doc comment to reflect removal of AuthProvider usage. |
| apps/vscode/src/providers/SettingsProvider.ts | Extends settings open command to accept an auth error banner message. |
| apps/vscode/src/providers/BarStatusProvider.ts | Routes auth-failed status bar action to Settings page. |
| apps/vscode/src/providers/AuthProvider.ts | Removes the standalone AuthProvider implementation. |
| apps/vscode/src/extension.ts | Stops registering AuthProvider. |
| apps/vscode/src/connection/connection.ts | Disconnects client on auth failure and opens Settings (focused + error). |
| apps/vscode/rsbuild.config.mjs | Removes the page-auth entry point from the VSCode webview build. |
| apps/shell-ui/src/workspace/useWorkspaceState.ts | Clears monitors + updates connection identity when switching apps. |
| apps/shell-ui/src/lib/Documents.tsx | Adds subscribe() and discardDocument() to support UI + deletion flows. |
| apps/shell-ui/src/components/layout/Shell.tsx | Sets a stable base clientName (“Cloud Shell-UI”). |
| apps/aparavi-ui/tsconfig.json | Adds aparavi-ui TS config targeting ES2022. |
| apps/aparavi-ui/src/pipe.d.ts | Enables importing .pipe files as JSON modules. |
| apps/aparavi-ui/src/index.ts | Switches to async boundary entry and loads the AppDescriptor. |
| apps/aparavi-ui/src/icon.svg | Adds app icon. |
| apps/aparavi-ui/src/docs.ts | Adds shared Documents singleton management for the app. |
| apps/aparavi-ui/src/chatStore.ts | Adds .chat file I/O helpers under .chats/. |
| apps/aparavi-ui/src/AppDescriptor.ts | Defines the Module Federation AppDescriptor for aparavi-ui. |
| apps/aparavi-ui/src/AparaviSidebar.tsx | Implements chat sidebar with Explorer-based chat file management. |
| apps/aparavi-ui/src/AparaviApp.tsx | Implements multi-tab chat UI, pipeline startup, and chat persistence logic. |
| apps/aparavi-ui/src/aparavi.pipe | Adds the pipeline that wires chat → agent → aparavi_aql tool → answers (+ chart tool). |
| apps/aparavi-ui/scripts/tasks.js | Adds builder module tasks config for aparavi-ui. |
| apps/aparavi-ui/rsbuild.config.mts | Adds RSBuild config for aparavi-ui as an MF remote. |
| apps/aparavi-ui/package.json | Adds app manifest + build dependencies for aparavi-ui. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Await clearAllMonitors() in switchApp to prevent monitor race on app switch
- Debounce-write chat messages to disk via saveChat() after updateContent()
- Replace vfs={null as any} with typed NOOP_VFS stub in AparaviSidebar
- Add allowFolders config to ExplorerConfig; chat sidebar sets false to hide
the "New Folder" button for flat .chat file lists
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Passed with exception of Mac which got a network error downloading torch |
Summary
This PR adds the Aparavi AQL integration end-to-end and fixes the VSCode auth/reconnect flow.
Aparavi AQL node
AQL SELECTstatements via the connected LLM, returns file metadata rows@tool_functiondecorators (current framework pattern),IInvokeLLM.Askfor LLM calls_aql_safeenforces single-statement SELECT-only queries with mutation keyword blockingAparavi chat app (aparavi-ui)
.chatJSON file via the workspace VFSuseChatMessageshook extended withinitialMessagesfor restoring saved conversationsAuth page removal & reconnect fix
AuthenticationException, callclient.disconnect()to stop thepersist:trueauto-reconnect loop with stale credentialsOther
Documents.discardDocument()for force-removing documents when backing file is deletedrole="dialog",aria-modal,aria-labelledbyfor accessibilitytabIndex+onKeyDownOriginal author
Aparavi AQL node originally by @blakewoodaparavi (PR #1147, closed due to fork push limitations). Modernized and extended in this PR.
Test plan
ruff check nodes/src/nodes/aparavi_aql/passes./builder test— node loads without import errorsGenerated with Claude Code